﻿//-----------------------------------------------------------------------
// <copyright file="App.xaml.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics.Silverlight.Studio
{
    using System;

    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;

    using System.Security;
    using System.Security.Principal;

    using System.Windows;

    using CodePlex.Diagnostics.Silverlight;

    /// <summary>
    /// Encapsulates the CodePlex.Diagnostics Silverlight application.
    /// </summary>
    public sealed partial class App : Application, ISecurityContext<IPrincipal>
    {
        #region public App()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:App"/> class.
        /// </summary>
        public App()
        {
            // establish the current Silverlight principal.
            this.CurrentPrincipal = new SilverlightPrincipal();

            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        #endregion

        #region private void Application_Startup(object sender, StartupEventArgs e)

        /// <summary>
        /// Handles the Startup event of the Application control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.Windows.StartupEventArgs"/> instance containing the event data.</param>
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.RootVisual = new MainPage();
        }

        #endregion

        #region private void Application_Exit(object sender, EventArgs e)

        /// <summary>
        /// Handles the Exit event of the Application control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void Application_Exit(object sender, EventArgs e)
        {
        }

        #endregion

        #region private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)

        /// <summary>
        /// Handles the UnhandledException event of the Application control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.Windows.ApplicationUnhandledExceptionEventArgs"/> instance containing the event data.</param>
        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // the browser's exception mechanism. On IE this will display it a yellow alert 
            // icon in the status bar and Firefox will display a script error.
            if (!Debugger.IsAttached)
            {
                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled. 
                // For production applications this error handling should be replaced with something that will 
                // report the error to the website and stop the application.
                e.Handled = true;
                Deployment.Current.Dispatcher.BeginInvoke(delegate { this.ReportErrorToDOM(e); });
            }
            else
            {
                Debugger.Break();

                Debug.WriteLine(e.ExceptionObject.Message);
                Debug.WriteLine(e.ExceptionObject.StackTrace);
            }
        }

        #endregion

        #region private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)

        /// <summary>
        /// Reports the error to DOM.
        /// </summary>
        /// <param name="e">The <see cref="T:System.Windows.ApplicationUnhandledExceptionEventArgs"/> instance containing the event data.</param>
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Code causing this rule violation was auto-generated by Visual Studio and will be refactored. Upon refactoring this rule suppression will be removed.")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Code causing this rule violation was auto-generated by Visual Studio and will be refactored. Upon refactoring this rule suppression will be removed.")]
        private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
        {
            try
            {
                string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
                errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");

                System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
            }
            catch (Exception)
            {
            }
        }

        #endregion

        #region public IPrincipal CurrentPrincipal

        /// <summary>
        /// Gets or sets the current principal of the Silverlight application.
        /// </summary>
        /// <value>The current principal of the Silverlight application.</value>
        public IPrincipal CurrentPrincipal
        {
            get;
            private set;
        }

        #endregion

        #region private sealed class SilverlightPrincipal : IPrincipal

        /// <summary>
        /// Allows code to check the role membership of a Silverlight user. 
        /// </summary>
        private sealed class SilverlightPrincipal : IPrincipal
        {
            #region public SilverlightPrincipal()

            /// <summary>
            /// Initializes a new instance of the <see cref="T:SilverlightPrincipal"/> class.
            /// </summary>
            public SilverlightPrincipal()
            {
                this.Identity = new SilverlightIdentity();
            }

            #endregion

            #region public IIdentity Identity

            /// <summary>
            /// Gets the identity of the current principal.
            /// </summary>
            /// <value>The identity of the current principal.</value>
            /// <returns>The <see cref="T:System.Security.Principal.IIdentity"/> object associated with the current principal.</returns>
            public IIdentity Identity
            {
                get;
                private set;
            }

            #endregion

            #region public bool IsInRole(string role)

            /// <summary>
            /// Determines whether the current principal belongs to the specified role.
            /// </summary>
            /// <param name="role">The name of the role for which to check membership.</param>
            /// <returns>
            /// <c>true</c> if the current principal is a member of the specified role; otherwise, <c>false</c>.
            /// </returns>
            public bool IsInRole(string role)
            {
                throw new NotImplementedException();
            }

            #endregion
        }

        #endregion

        #region private sealed class SilverlightIdentity : IIdentity

        /// <summary>
        /// Represents a Silverlight user. 
        /// </summary>
        private sealed class SilverlightIdentity : IIdentity
        {
            #region public SilverlightIdentity()

            /// <summary>
            /// Initializes a new instance of the <see cref="T:SilverlightIdentity"/> class.
            /// </summary>
            public SilverlightIdentity()
            {
                this.AuthenticationType = "Silverlight";
                
                this.IsAuthenticated = false;

                this.Name = "Unknown";
            }

            #endregion

            #region public string AuthenticationType

            /// <summary>
            /// Gets the type of authentication used.
            /// </summary>
            /// <value></value>
            /// <returns>The type of authentication used to identify the user.</returns>
            public string AuthenticationType
            {
                get;
                private set;
            }

            #endregion

            #region public bool IsAuthenticated

            /// <summary>
            /// Gets a value that indicates whether the user has been authenticated.
            /// </summary>
            /// <value></value>
            /// <returns>true if the user was authenticated; otherwise, false.</returns>
            public bool IsAuthenticated
            {
                get;
                private set;
            }

            #endregion

            #region public string Name

            /// <summary>
            /// Gets the name of the current user.
            /// </summary>
            /// <value></value>
            /// <returns>The name of the user on whose behalf the code is running.</returns>
            public string Name
            {
                get;
                private set;
            }

            #endregion
        }

        #endregion
    }
}
